package com.tool;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * 数据中心持久层实现
 * 
 * @author Evan.Hu
 * 
 */
public class DataCenterPersistence {
	private static final String CHARSET_UTF_8 = "UTF-8";
	/**
	 * 数据中心列表
	 */
	private static List<DataCenterVO> dcList = new ArrayList<DataCenterVO>();
	/**
	 * 文件最后修改时间
	 */
	private static long lastModifiedTime = 0L;
	/**
	 * 持久层文件路径
	 */
	private static String FILE_PATH = "./config/DataCenter.p";

	static {
		File configFile = new File(FILE_PATH);
		if (!configFile.exists()) {
			// 配置文件不存在，先生成文件
			saveData();
		}

	}

	/**
	 * 数据中心注册
	 * 
	 * @param dcVo
	 */
	public static void register(DataCenterVO dcVo) {
		loadData();

		if (dcList.contains(dcVo)) {
			throw new RuntimeException("已经存在相同编码数据中心，请重新输入数据中心编码");
		}

		dcList.add(dcVo);
		saveData();

	}

	/**
	 * 数据中心反注册
	 * 
	 * @param dcVo
	 */
	public static void unRegister(DataCenterVO dcVo) {
		loadData();

		if (!dcList.contains(dcVo)) {
			throw new RuntimeException("指定编码数据中心不存在或已删除");
		}

		dcList.remove(dcVo);
		saveData();
	}

	/**
	 * 获取当前数据中心列表
	 * 
	 * @return
	 */
	public static List<DataCenterVO> getDCList() {
		loadData();

		return dcList;
	}

	/**
	 * 保存数据
	 */
	private static void saveData() {
		BufferedWriter bw = null;
		try {
			bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FILE_PATH), CHARSET_UTF_8));
			if (dcList != null) {
				for (int i = 0, size = dcList.size(); i < size; i++) {
					if (i != 0) {
						// 非第一行，都得换行
						bw.newLine();
					}
					DataCenterVO dcVo = dcList.get(i);
					bw.write(encryptData(encode(dcVo)));
				}
			}
			bw.flush();
		} catch (Exception ee) {
			ee.printStackTrace();
		} finally {
			if (bw != null)
				try {
					bw.close();
				} catch (IOException e) {
				}
		}
	}

	/**
	 * 加载数据
	 */
	private static void loadData() {
		if (lastModifiedTime != new File(FILE_PATH).lastModified()) {
			// 文件未更改过，不需要重新加载
			BufferedReader br = null;
			try {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(FILE_PATH), CHARSET_UTF_8));
				// 先清除数据
				dcList.clear();
				String line;
				while ((line = br.readLine()) != null) {
					dcList.add(decode(decryptData(line)));
				}

				lastModifiedTime = new File(FILE_PATH).lastModified();
			} catch (RuntimeException ee) {
				throw ee;
			} catch (Exception ee) {
				ee.printStackTrace();
				throw new RuntimeException("数据中心文件已经损坏，请联系管理员");
			} finally {
				try {
					if (br != null)
						br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * @param vo
	 * @return
	 */
	public static String encode(DataCenterVO vo) {
		StringBuilder buf = new StringBuilder();
		buf.append(vo.getDbType()).append("||");
		buf.append(vo.getDbAddr()).append("||");
		buf.append(vo.getDbPort()).append("||");
		buf.append(vo.getUserName()).append("||");
		buf.append(vo.getPassword()).append("||");
		buf.append(vo.getDbName()).append("||");
		buf.append(vo.getDcNumber()).append("||");
		buf.append(vo.getDcName());
		return buf.toString();
	}

	/**
	 * @param str
	 * @return
	 */
	public static DataCenterVO decode(String str) {
		if (str == null)
			return null;
		String[] vs = str.split("\\|\\|");
		if (vs.length != 8)
			throw new RuntimeException("数据中心文件已经损坏，请联系管理员");

		DataCenterVO vo = new DataCenterVO();
		vo.setDbType(Integer.parseInt(vs[0]));
		vo.setDbAddr(vs[1]);
		vo.setDbPort(vs[2]);
		vo.setUserName(vs[3]);
		vo.setPassword(vs[4]);
		vo.setDbName(vs[5]);
		vo.setDcNumber(vs[6]);
		vo.setDcName(vs[7]);

		return vo;
	}

	/**
	 * @param input
	 * @return
	 * @throws Exception
	 */
	public static String encryptData(String input) throws Exception {

		SecureRandom sr = new SecureRandom();
		byte rawKeyData[] = "ACDFHJLN".getBytes();
		DESKeySpec dks = new DESKeySpec(rawKeyData);

		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		SecretKey key = keyFactory.generateSecret(dks);

		Cipher c = Cipher.getInstance("DES");
		c.init(Cipher.ENCRYPT_MODE, key, sr);
		byte[] cipherByte = c.doFinal(input.getBytes());
		String dec = new BASE64Encoder().encode(cipherByte);
		// 保证不存在换行的问题
		return dec.replaceAll("\r\n", "||");
	}

	/**
	 * @param input
	 * @return
	 * @throws Exception
	 */
	public static String decryptData(String input) throws Exception {
		// 将密文 中存在的换行还原回去
		byte[] dec = new BASE64Decoder().decodeBuffer(input.replaceAll("\\|\\|", "\r\n"));

		SecureRandom sr = new SecureRandom();
		byte rawKeyData[] = "ACDFHJLN".getBytes();

		DESKeySpec dks = new DESKeySpec(rawKeyData);

		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");

		SecretKey key = keyFactory.generateSecret(dks);

		Cipher c = Cipher.getInstance("DES");
		c.init(Cipher.DECRYPT_MODE, key, sr);
		byte[] clearByte = c.doFinal(dec);

		return new String(clearByte);

	}

	private static String to_UTF8(String key) throws UnsupportedEncodingException {
		return key == null ? null : new String(key.getBytes(), CHARSET_UTF_8);
	}

	public static void main(String[] args) {

		getDCList();
	}

}
